#include "ircbot.h"

#define DEBUG

//376 end of motd
//422 is missing motd
BOOL irc_connect(irc_info_t *irc_info) {
	struct hostent		*host;
	struct sockaddr_in	server_info;
	int					ret, size;
	char				*buf, *wat;
	if(!irc_info) return FALSE;

	irc_info->sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(irc_info->sockfd != -1) {
		host = gethostbyname((char *)irc_info->server);
		if(host != NULL){
			server_info.sin_family	= AF_INET;
			server_info.sin_addr	= *((struct in_addr *)*host->h_addr_list);
			server_info.sin_port	= htons(irc_info->port);
			ret = connect(irc_info->sockfd, 
					(struct sockaddr *)&server_info, 
					sizeof(struct sockaddr));
			if(ret != -1) {
				// good to to
				

				size = strlen(irc_info->nick);
				buf = malloc(sizeof(char) * (size + 8)); // + 8 for "NICK ", \r\n and NUL.
				snprintf(buf, size + 8, "NICK %s\r\n", irc_info->nick);
				irc_write_raw(irc_info, buf);

				size = strlen(irc_info->user);
				buf = realloc(buf, sizeof(char) * (size * 2 + 14)); // + 14 for "USER ", " 8 * :", \r\n and NUL.
				snprintf(buf, size * 2 + 14, "USER %s 8 * :%s\r\n", irc_info->user, irc_info->user);
				irc_write_raw(irc_info, buf);
				
				buf = realloc(buf, sizeof(char) * MAX_LEN);
				while(irc_read(irc_info, buf)) {
#ifdef DEBUG
					printf("buf:\n%s\n\n", buf);
#endif
					//TODO: stop using strtok(), it's bad when it comes to multi-threadedness
					if( (wat = strtok(buf, " ")) != NULL && (wat = strtok(NULL, " ")) != NULL) {
						if(!strncmp(wat, "376", 3) || !strncmp(wat, "422", 3) ) {
							irc_info->channels = init_channel();
							return TRUE;
						}
						//TODO:  check for failed connections.
					}
				}
				free(buf);
				return TRUE;	
			} 
		} 
	} 
	return FALSE;
}


void irc_part(irc_info_t *irc_info, char *channel) {
	char *outgoing;
	int length;
	if(!irc_info || !channel) return;
	if(contains_channel(irc_info->channels, channel)) {
		length = strlen(channel);
		outgoing = malloc(sizeof(char) * (length + 8)); // +8 for "PART " \r\n and \0
		snprintf(outgoing, length + 8, "PART %s\r\n", channel);
		irc_write_raw(irc_info, outgoing);
		free(outgoing);
		remove_channel(irc_info->channels, channel);
	}
}

// 366 end of /names
// 332 idk but it's the first one that I get 
// 403 unknown channel
BOOL irc_join(irc_info_t *irc_info, char *channel) {
	char incoming[MAX_LEN], *wat, *outgoing;
	int length;
	if(!irc_info) return FALSE;
#ifdef DEBUG
	printf("Attempting to join %s\n", channel);
#endif
	// send the join message to the server
	length = strlen(channel);
	outgoing = malloc(sizeof(char) * (length + 8));  // +8 for "JOIN " and \r\n and '\0'
	snprintf(outgoing, length + 8, "JOIN %s\r\n", channel);
	if(!irc_write_raw(irc_info, outgoing)){
		free(outgoing);
		return FALSE;
	}
	free(outgoing);

	// check numeric responses to see if join worked
	while(irc_read(irc_info, incoming)) {
		wat = strtok(incoming, " ");
		if(wat != NULL) {
			wat = strtok(NULL, " "); // 
			if(wat != NULL) {
				if(!strncmp(wat, "366", 3) || !strncmp(wat, "332", 3) || !strncmp(wat, "376", 3)) {
					// add the channel to the channels struct if we've connected
					add_channel(irc_info->channels, channel);
					return TRUE;
				}
				else if(!strncmp(wat, "403", 3))
					return FALSE;
			}
		}
	}

	return FALSE;
}

BOOL irc_read(irc_info_t *irc_info, char *incoming) {
	int		ret, size, bytes_read = 0;
	char	read[2], *line, *outgoing;
	if(!irc_info) return FALSE;

	line = malloc(sizeof(char) * bytes_read + 1);
	while(bytes_read < MAX_LEN) {
		ret = recv(irc_info->sockfd, read, 1, 0);
		if(ret >= 0) {
			bytes_read += ret;
			line = realloc(line, sizeof(char) * bytes_read + 1);
			line[bytes_read - 1] = read[0];
			if(read[0] == '\n')
				break;
		} else {
			return FALSE;
		}
	}
	line[bytes_read] = '\0';
	strncpy(incoming, line, bytes_read);
	incoming[bytes_read] = '\0';
	free(line);

	if(ret >= 0) {
		// check for pings
		if(!strncmp(incoming, "PING ", 5)) {
			size = strlen(incoming) - 4; // minus 4 because "PING " is five chars, and we need a NUL terminator.
			outgoing = malloc(sizeof(char) * size + 8); 
			snprintf(outgoing, size + 8, "PONG %s\r\n", &incoming[4]);
			irc_write_raw(irc_info, outgoing);
			free(outgoing);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL irc_write_raw(irc_info_t *irc_info, char *write) {
	if(!irc_info || !write) return FALSE;
	if(send(irc_info->sockfd, write, strlen(write), 0) >= 0) { 
		return TRUE;
	}
	return FALSE;
}
